package io.p2p.stream.dispatch.handler;

import com.alibaba.fastjson.JSONObject;
import common.core.domain.udp.UdpApiProtocol;
import io.netty.buffer.Unpooled;
import io.netty.channel.socket.DatagramPacket;
import io.p2p.stream.dispatch.model.ClientSharedModel;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class NatCheckAckHandler{
    private UdpApiProtocol apiProtocol;

    public NatCheckAckHandler(UdpApiProtocol apiProtocol) {
        this.apiProtocol = apiProtocol;
    }

    private static AtomicBoolean step2Success = new AtomicBoolean(false);
    private static AtomicBoolean step4Success = new AtomicBoolean(false);
    private static AtomicBoolean step6Success = new AtomicBoolean(false);

    public void natCheckAck() {
         boolean checked = apiProtocol.getBuffer().getBooleanValue("checked");

         if(checked){
             int natType = apiProtocol.getBuffer().getIntValue("natType");
             ClientSharedModel.natType.set(natType);
         }else{
             String step = apiProtocol.getBuffer().getString("step");
             switch(step){
                 case "step1":
                     step1();
                     break;
                 case "step2":
                     step2();
                     break;
                 case "step3":
                     step3();
                     break;
                 case "step4":
                     step4();
                     break;
                 case "step5":
                     step5();
                     break;
                 case "step6":
                     step6();
                     break;
                 case "step7":
                     step7();
                     break;
                 case "step8":
                     step8();
                     break;
             }
         }
    }

    private void step1(){

    }

    private void step2(){
        step2Success.set(true);
    }

    private void step3(){
        AtomicInteger count = new AtomicInteger(60);
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(()->{
             if(step2Success.get()){
                 JSONObject natCheck = new JSONObject();
                 natCheck.put("type", "natCheck");
                 natCheck.put("subType", "step2");
                 natCheck.put("name", ClientSharedModel.loginName);

                 apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(), StandardCharsets.UTF_8),
                         apiProtocol.getRemoteAddress()));
                 scheduler.shutdown();
                 return;
             }

             if(count.decrementAndGet() == 0 && !step2Success.get()){
                 JSONObject natCheck = new JSONObject();
                 natCheck.put("type", "natCheck");
                 natCheck.put("subType", "step3");
                 natCheck.put("name", ClientSharedModel.loginName);

                 apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(), StandardCharsets.UTF_8),
                         apiProtocol.getRemoteAddress()));

                 scheduler.shutdown();
             }
        },0, 100, TimeUnit.MILLISECONDS);
    }

    private void step4(){
        step4Success.set(true);
    }

    private void step5(){
        AtomicInteger count = new AtomicInteger(60);
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(()->{
            if(step4Success.get()){
                JSONObject natCheck = new JSONObject();
                natCheck.put("type", "natCheck");
                natCheck.put("subType", "step4");
                natCheck.put("name", ClientSharedModel.loginName);

                apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(), StandardCharsets.UTF_8),
                        apiProtocol.getRemoteAddress()));
                scheduler.shutdown();
                return;
            }

            if(count.decrementAndGet() == 0 && !step4Success.get()){
                JSONObject natCheck = new JSONObject();
                natCheck.put("type", "natCheck");
                natCheck.put("subType", "step5");
                natCheck.put("name", ClientSharedModel.loginName);

                apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(),StandardCharsets.UTF_8),
                        new InetSocketAddress(ClientSharedModel.mainServerSecondIP,ClientSharedModel.mainServerSecondPort)));

                apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(),StandardCharsets.UTF_8),
                        apiProtocol.getRemoteAddress()));

                scheduler.shutdown();
            }
        },0, 100, TimeUnit.MILLISECONDS);
    }

    private void step6(){
        step6Success.set(true);
    }

    private void step7(){
        AtomicInteger count = new AtomicInteger(60);
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(()->{
            if(step6Success.get()){
                JSONObject natCheck = new JSONObject();
                natCheck.put("type", "natCheck");
                natCheck.put("subType", "step6");
                natCheck.put("name", ClientSharedModel.loginName);

                apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(),StandardCharsets.UTF_8),
                        apiProtocol.getRemoteAddress()));
                scheduler.shutdown();
                return;
            }

            if(count.decrementAndGet() == 0 && !step6Success.get()){
                JSONObject natCheck = new JSONObject();
                natCheck.put("type", "natCheck");
                natCheck.put("subType", "step7");
                natCheck.put("name", ClientSharedModel.loginName);

                apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(),StandardCharsets.UTF_8),
                        apiProtocol.getRemoteAddress()));
                scheduler.shutdown();
            }
        },0, 100, TimeUnit.MILLISECONDS);
    }

    private void step8(){
        step2Success.set(false);
        step4Success.set(false);
        step6Success.set(false);

        if(ClientSharedModel.checkNatCount.decrementAndGet() > 0){
            JSONObject natCheck = new JSONObject();
            natCheck.put("type","natCheck");
            natCheck.put("subType","step1");
            natCheck.put("name",ClientSharedModel.loginName);

            apiProtocol.getCtx().writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(natCheck.toJSONString(),StandardCharsets.UTF_8),
                    new InetSocketAddress(ClientSharedModel.stunServerIP,ClientSharedModel.stunServerPort)));
        }
    }
}
